package accountManagement;

import java.io.IOException;
import java.io.Serializable;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;

import common.ObjectFileStoring;
import common.Storing;

public class AccountManager implements Serializable {
	private static final long serialVersionUID = -5744242105491198906L;

	private static final AccountManager reference = new AccountManager();
	private Storing<Account> fileStoring;
	
	private static final String PATHNAME = ".";
	private static final String FILENAME = "AccountManager";
	
	private AccountManager() {
		fileStoring = new ObjectFileStoring<Account>(PATHNAME, FILENAME);
	}
	
	public static AccountManager getInstance() {
		return reference;
	}

	private int getAccountIndex(List<Account> accountList, Account account) {
		int index = 0;
		
		while(index < accountList.size() && !accountList.get(index).equals(account)) {
			index++;
		}
		
		if(index >= accountList.size()) {
			// account non presente nella lista
			index = -1;
		}
		
		return index;
	}
	
	public synchronized void add(Account account) throws InvalidParameterException {
		if(account == null) {
			throw new InvalidParameterException("Account is null!");
		}
		// Caricamento
		List<Account> accountList = getAccountList();
		

		// Operazione
		int index = getAccountIndex(accountList, account);
		if(index != -1) {
			throw new InvalidParameterException("Existing account!");
		}
		accountList.add(account);

		// Salvataggio
		try {
			fileStoring.save(accountList);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public List<Account> search(Account account) throws InvalidParameterException {
		if(account == null) {
			throw new InvalidParameterException("Account is null!");
		}
		// Caricamento
		List<Account> accountList = getAccountList();
		
		// Operazione
		List<Account> resultList = new ArrayList<Account>();
		for(Account accountTmp : accountList) {
			boolean match = false;
			
			if(account.getNickname() != null && accountTmp.getNickname().contains(account.getNickname()))
				match = true;
			
			if(accountTmp instanceof Client && account instanceof Client) {
				if(((Client) account).getSurname() != null && ((Client) accountTmp).getSurname().contains(((Client) account).getSurname()))
					match = true;
				
				if(((Client) account).getName() != null && ((Client) accountTmp).getName().contains(((Client) account).getName()))
					match = true;
				
				if(((Client) account).getFiscalCode() != null && ((Client) accountTmp).getFiscalCode().contains(((Client) account).getFiscalCode()))
					match = true;
			}

			if(accountTmp instanceof Employee && account instanceof Employee) {
				if(((Employee) account).getEmployeeId() != null && 
						((Employee) accountTmp).getEmployeeId().contains(((Employee) account).getEmployeeId()))
					match = true;
			}
			
			if(match)
				resultList.add(accountTmp);
		}

		return resultList;
	}
	
	public synchronized void modify(Account iniziale, Account modificato) throws InvalidParameterException {
		if(iniziale == null || modificato == null) {
			throw new InvalidParameterException("iniziale or modificato are null!");
		}
		// Caricamento
		List<Account> accountList = getAccountList();
		
		// Operazione
		int index = getAccountIndex(accountList, iniziale);
		if(index != -1) {
			throw new InvalidParameterException("Existing account!");
		}
		if(modificato.getNickname() != null)
			accountList.get(index).setNickname(modificato.getNickname());
		
		if(modificato.getPassword() != null)
			accountList.get(index).setPassword(modificato.getPassword());
		
		if(iniziale instanceof Client && modificato instanceof Client) {
			if(((Client) modificato).getSurname() != null)
				((Client) accountList.get(index)).setSurname(((Client) modificato).getSurname());

			if(((Client) modificato).getName() != null)
				((Client) accountList.get(index)).setName(((Client) modificato).getName());

			if(((Client) modificato).getFiscalCode() != null)
				((Client) accountList.get(index)).setFiscalCode(((Client) modificato).getFiscalCode());
		}

		if(iniziale instanceof Employee && modificato instanceof Employee) {
			if(((Employee) modificato).getEmployeeId() != null)
				((Employee) accountList.get(index)).setEmployeeId(((Employee) modificato).getEmployeeId());
		}
		
		// Salvataggio
		try {
			fileStoring.save(accountList);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public synchronized void remove(Account account) throws InvalidParameterException {
		if(account == null) {
			throw new InvalidParameterException("Account is null!");
		}
		// Caricamento
		List<Account> accountList = getAccountList();
				
		// Operazione
		int index = getAccountIndex(accountList, account);
		if(index == -1) {
			throw new InvalidParameterException("Inexisting account!");
		}
		accountList.remove(index);

		// Salvataggio
		try {
			fileStoring.save(accountList);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public Account checkLogin(String nickname, String password) throws InvalidParameterException {
		if(nickname == null || password == null) {
			throw new InvalidParameterException("nickname and password must be not null!");
		}
		// Caricamento
		List<Account> accountList = getAccountList();
		
		// Operazione
		Account account = new Account(nickname, password);
		int index = getAccountIndex(accountList, account);
		
		if(index != -1 && accountList.get(index).checkPassword(password)) {
			// account esistente e credenziali valide
			account = accountList.get(index);
			System.out.println("password valida: " + account);
		} else {
			account = null;
		}
		return account;
	}

	public List<Account> getAccountList() {
		// Caricamento
		List<Account> accountList;
		try {
			accountList = (List<Account>) fileStoring.load();
		} catch(IOException e) {
			accountList = new ArrayList<Account>();
			accountList.add(new Admin("admin", "admin"));
			accountList.add(new Client("client", "client", "Lauri", "Giuseppe Giovanni", "CODFIS"));
			accountList.add(new Employee("employee", "employee", "emp1"));
			// Salvataggio
			try {
				fileStoring.save(accountList);
			} catch (IOException ex) {
				e.printStackTrace();
			}
		}
		System.out.println("Lista: " + accountList);
		return accountList;
	}
}
